package store.lunangangster.engine.impl.el;

import de.odysseus.el.ExpressionFactoryImpl;
import javax.el.ArrayELResolver;
import javax.el.BeanELResolver;
import javax.el.CompositeELResolver;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ExpressionFactory;
import javax.el.ListELResolver;
import javax.el.MapELResolver;
import javax.el.ResourceBundleELResolver;
import javax.el.ValueExpression;
import org.apache.commons.lang3.StringUtils;
import store.lunangangster.engine.NodeFlowException;
import store.lunangangster.engine.ProcessEngineConfiguration;
import store.lunangangster.engine.impl.entity.mgr.VariableScope;

public class ExpressManager {

  // de.odysseus.el.ExpressionFactoryImpl
  protected ProcessEngineConfiguration processEngineConfiguration;
  protected ExpressionFactory expressionFactory = new ExpressionFactoryImpl();

  public ExpressManager(ProcessEngineConfiguration processEngineConfiguration) {
    this.processEngineConfiguration = processEngineConfiguration;
  }


  public Expression createExpression(String expression, Class<?> expectType) {
    return createExpression(expression, expectType, null);
  }

  // Thread Safe
  public Expression createExpression(String expression, Class<?> expectType, VariableScope variableScope) {
    ELContext context = createDefaultElContext(variableScope);
    ValueExpression valueExpression = expressionFactory.createValueExpression(context, expression,
        expectType);
    return new DefaultExpression(context, valueExpression);
  }

  public boolean evalExpression(String conditionExpression, VariableScope variableScope) {
    if (StringUtils.isBlank(conditionExpression)) {
      return true;
    }
    try {
      Expression expression = createExpression(conditionExpression, boolean.class, variableScope);
      return (boolean) expression.getValue();
    } catch (ELException e) {
      throw new NodeFlowException("错误的计算结果类型：SequenceFlow中的ConditionExpression的结果应为boolean类型");
    }
  }

  protected CompositeELResolver createDefaultElResolvers() {
    CompositeELResolver elResolver = new CompositeELResolver();
    elResolver.add(new ArrayELResolver(true));
    elResolver.add(new ListELResolver(true));
    elResolver.add(new MapELResolver(true));
    elResolver.add(new ResourceBundleELResolver());
    elResolver.add(new BeanELResolver(true));
    return elResolver;
  }

  protected ELContext createDefaultElContext(VariableScope variableScope) {
    return new DefaultContext(createDefaultElResolvers(), variableScope, expressionFactory);
  }
}
